#include "dspSimulator/instruction/SPMASK.h"

namespace dspsimulator {

    std::string SPMASK::to_string() const {
        std::string str = m_name + " ";
        for (const auto &func_unit: m_masked_function_unit) {
            str += get_function_unit_name(func_unit) + " ";
        }
        return str;
    }

    std::shared_ptr<DspInstruction>
    SPMASK::decode_standard_instruction(const std::shared_ptr<DspInstructionInfo> &dsp_instruction_info) {
        std::shared_ptr<SPMASK> spmask;
        std::bitset<32> &data = dsp_instruction_info->m_standard_bits;
        if (common::check_bits<6>(data, 0b000000, 26)
            && common::check_bits<3>(data, 0b110, 15)
            && common::check_bits<12>(data, 0b000000000000, 2)) {
            spmask = std::make_shared<SPMASK>(dsp_instruction_info->address(), 4);
            bool L1 = data[18];
            if (L1) {
                spmask->m_masked_function_unit.emplace_back(FuncUnit::L1);
            }
            bool L2 = data[19];
            if (L2) {
                spmask->m_masked_function_unit.emplace_back(FuncUnit::L2);
            }
            bool S1 = data[20];
            if (S1) {
                spmask->m_masked_function_unit.emplace_back(FuncUnit::S1);
            }
            bool S2 = data[21];
            if (S2) {
                spmask->m_masked_function_unit.emplace_back(FuncUnit::S2);
            }
            bool D1 = data[22];
            if (D1) {
                spmask->m_masked_function_unit.emplace_back(FuncUnit::D1);
            }
            bool D2 = data[23];
            if (D2) {
                spmask->m_masked_function_unit.emplace_back(FuncUnit::D2);
            }
            bool M1 = data[24];
            if (M1) {
                spmask->m_masked_function_unit.emplace_back(FuncUnit::M1);
            }
            bool M2 = data[25];
            if (M2) {
                spmask->m_masked_function_unit.emplace_back(FuncUnit::M2);
            }
            spmask->m_p = data[0];
        }
        return spmask;
    }

    std::shared_ptr<DspInstruction>
    SPMASK::decode_compact_instruction(const std::shared_ptr<DspInstructionInfo> &dsp_instruction_info) {
        std::shared_ptr<SPMASK> spmask;
        std::bitset<16> &data = dsp_instruction_info->m_compact_bits;
        if (common::check_bits<4>(data, 0b1011, 10) && common::check_bits<6>(data, 0b110011, 1)) {
            spmask = std::make_shared<SPMASK>(dsp_instruction_info->address(), 2);
            bool L1 = data[0];
            if (L1) {
                spmask->m_masked_function_unit.emplace_back(FuncUnit::L1);
            }
            bool L2 = data[7];
            if (L2) {
                spmask->m_masked_function_unit.emplace_back(FuncUnit::L2);
            }
            bool S1 = data[8];
            if (S1) {
                spmask->m_masked_function_unit.emplace_back(FuncUnit::S1);
            }
            bool S2 = data[9];
            if (S2) {
                spmask->m_masked_function_unit.emplace_back(FuncUnit::S2);
            }
            bool D1 = data[14];
            if (D1) {
                spmask->m_masked_function_unit.emplace_back(FuncUnit::D1);
            }
            bool D2 = data[15];
            if (D2) {
                spmask->m_masked_function_unit.emplace_back(FuncUnit::D2);
            }
            spmask->m_p = dsp_instruction_info->p();
        }
        return spmask;
    }

    bool SPMASK::masked(const std::shared_ptr<DspInstruction> &instruction) const {
        if (instruction == nullptr) {
            return true;
        }
        if (instruction->name() == "BNOP") {
            return true;
        }
        if (std::find(m_masked_function_unit.begin(), m_masked_function_unit.end(), instruction->m_func_unit) !=
            m_masked_function_unit.end()) {
            return true;
        }
        return false;
    }
}